package com.googlecode.microanalyst.designer.edit;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionRouter;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ManhattanConnectionRouter;
import org.eclipse.draw2d.RelativeBendpoint;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.swt.accessibility.AccessibleEvent;

import com.googlecode.microanalyst.designer.figures.FigureFactory;
import com.googlecode.microanalyst.designer.i18n.DesignerMessages;
import com.googlecode.microanalyst.designer.model.AnalysisConnection;
import com.googlecode.microanalyst.designer.model.AnalysisConnectionBendpoint;

/**
 * Implements a Connection Editpart to represnt a Wire like connection.
 * 
 */
public class AnalysisConnectionEditPart extends AbstractConnectionEditPart
		implements PropertyChangeListener {

	AccessibleEditPart acc;

	public void activate() {
		super.activate();
		getConnection().addPropertyChangeListener(this);
	}

	public void deactivate() {
		getConnection().removePropertyChangeListener(this);
		super.deactivate();
	}

	public void activateFigure() {
		super.activateFigure();
		/*
		 * Once the figure has been added to the ConnectionLayer, start
		 * listening for its router to change.
		 */
		getFigure().addPropertyChangeListener(
				Connection.PROPERTY_CONNECTION_ROUTER, this);
	}
	
	public void deactivateFigure() {
		getFigure().removePropertyChangeListener(
				Connection.PROPERTY_CONNECTION_ROUTER, this);
		super.deactivateFigure();
	}

	/**
	 * Adds extra EditPolicies as required.
	 */
	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE,
				new AnalysisConnectionEndpointEditPolicy());
		// Note that the Connection is already added to the diagram and knows
		// its Router.
		refreshBendpointEditPolicy();
		installEditPolicy(EditPolicy.CONNECTION_ROLE,
				new AnalysisConnectionEditPolicy());
	}

	/**
	 * Returns a newly created Figure to represent the connection.
	 * 
	 * @return The created Figure.
	 */
	protected IFigure createFigure() {
		AnalysisConnection connection = getConnection();
		Connection connx = FigureFactory
				.createNewBendableAnalysisConnection(connection);
		return connx;
	}

	public AccessibleEditPart getAccessibleEditPart() {
		if (acc == null)
			acc = new AccessibleGraphicalEditPart() {
				public void getName(AccessibleEvent e) {
					e.result = DesignerMessages.AnalysisConnection_LabelText;
				}
			};
		return acc;
	}

	/**
	 * Returns the model of this represented as a Connection.
	 * 
	 * @return Model of this as <code>AnalysisConnection</code>
	 */
	protected AnalysisConnection getConnection() {
		return (AnalysisConnection) getModel();
	}

	/**
	 * Listens to changes in properties of the Wire (like the contents being
	 * carried), and reflects is in the visuals.
	 * 
	 * @param event
	 *            Event notifying the change.
	 */
	public void propertyChange(PropertyChangeEvent event) {
		String property = event.getPropertyName();
		if (Connection.PROPERTY_CONNECTION_ROUTER.equals(property)) {
			refreshBendpoints();
			refreshBendpointEditPolicy();
		}
		if ("value".equals(property)) //$NON-NLS-1$
			refreshVisuals();
		if ("bendpoint".equals(property)) //$NON-NLS-1$
			refreshBendpoints();
	}

	/**
	 * Updates the bendpoints, based on the model.
	 */
	protected void refreshBendpoints() {
		Connection connectionFigure = getConnectionFigure();
		if (connectionFigure.getConnectionRouter() instanceof ManhattanConnectionRouter)
			return;
		List<AnalysisConnectionBendpoint> modelConstraint = getConnection()
				.getBendpoints();
		List<RelativeBendpoint> figureConstraint = new ArrayList<RelativeBendpoint>();
		for (int i = 0; i < modelConstraint.size(); i++) {
			AnalysisConnectionBendpoint wbp = (AnalysisConnectionBendpoint) modelConstraint
					.get(i);
			RelativeBendpoint rbp = new RelativeBendpoint(connectionFigure);
			Dimension rd1 = wbp.getFirstRelativeDimension();
			Dimension rd2 = wbp.getSecondRelativeDimension();
			rbp.setRelativeDimensions(rd1, rd2);
			float weight = (i + 1) / ((float) modelConstraint.size() + 1);
			rbp.setWeight(weight);
			figureConstraint.add(rbp);
		}
		connectionFigure.setRoutingConstraint(figureConstraint);
	}

	private void refreshBendpointEditPolicy() {
		Connection connectionFigure = getConnectionFigure();
		ConnectionRouter connectionRouter = connectionFigure
				.getConnectionRouter();
		if (connectionRouter instanceof ManhattanConnectionRouter)
			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE, null);
		else {
			AnalysisConnectionBendpointEditPolicy policy = new AnalysisConnectionBendpointEditPolicy();
			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE, policy);
		}
	}

	/**
	 * Refreshes the visual aspects of this, based upon the model (Wire). It
	 * changes the wire color depending on the state of Wire.
	 * 
	 */
	protected void refreshVisuals() {
		refreshBendpoints();
	}

}
